package com.diy.sigmund.diyuser.common.middleware.easyexcel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author ylm-sigmund
 * @since 2023/4/20 18:57
 */
public class ExportExcelListener<T> {

    private BaseMapper<T> baseMapper;

    public ExportExcelListener(BaseMapper<T> baseMapper) {
        this.baseMapper = baseMapper;
    }

    private static final String DATA_FORMAT = "yyyy-MM-dd-HH-mm-ss";

    private static final String CHARACTER_UTF_8 = "UTF-8";

    private static final String CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

    private static final String CONTENT_DISPOSITION = "Content-Disposition";

    private static final int PAGE_SIZE = 10000;
    private static final Logger log = LoggerFactory.getLogger(ExportExcelListener.class);

    public void exportExcel(HttpServletResponse response, String sheetName, Class<T> pojoClass,
            LambdaQueryWrapper<T> queryWrapper) throws IOException {
        ServletOutputStream out = getServletOutputStream(response, sheetName);
        // 这里 需要指定写用哪个class去写
        ExcelWriter excelWriter = EasyExcel.write(out, pojoClass).build();
        // 这里注意 如果同一个sheet只要创建一次
        WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();

        // int totalCount = Math.toIntExact(baseMapper.selectCount(queryWrapper));
        int totalCount = 5_0000;

        int pageNumber = (int) Math.ceil((double) totalCount / (double) PAGE_SIZE);    //分页条数看情况

        // 去调用写入,根据数据库分页的总的页数来
        for (int i = 1; i <= pageNumber; i++) {
            //先定义一个空集合每次循环使他变成null减少内存的占用
            List<T> recordList = new ArrayList<>();
            Page<T> page = new Page<>(i, PAGE_SIZE);
            Page<T> pojoIPage = baseMapper.selectPage(page, queryWrapper);
            recordList = pojoIPage.getRecords();
            excelWriter.write(recordList, writeSheet);
            recordList.clear();
        }
        // 千万别忘记finish 会帮忙关闭流
        excelWriter.finish();
        out.flush();
    }

    /**
     * 查询优化的方法
     */
    public void exportNoQueryCount(HttpServletResponse response, String sheetName, Class<T> pojoClass,
            LambdaQueryWrapper<T> queryWrapper) throws IOException {
        ServletOutputStream out = getServletOutputStream(response, sheetName);
        ExcelWriter excelWriter = EasyExcel.write(out, pojoClass).build();

        WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
        int startIndex = 1;
        while (true) {
            int startParam = (startIndex - 1) * PAGE_SIZE;
            int pageNumber = (int) Math.ceil((double) startParam / (double) PAGE_SIZE + 1);
            Page<T> page = new Page<>(pageNumber, PAGE_SIZE, false);
            Page<T> pojoIPage = baseMapper.selectPage(page, queryWrapper);
            List<T> recordList = pojoIPage.getRecords();
            // if (startIndex >= 2) {
            //     break;
            // }
            if (CollectionUtils.isEmpty(recordList)) {
                break;
            }
            startIndex++;
            excelWriter.write(recordList, writeSheet);

        }
        log.info("导出x万数据：{}", --startIndex);
        // 千万别忘记finish 会帮忙关闭流
        excelWriter.finish();
    }

    public static ServletOutputStream getServletOutputStream(HttpServletResponse response, String sheetName) throws IOException {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATA_FORMAT);
        String nowTime = formatter.format(LocalDateTime.now());
        String fileName = sheetName.concat("_").concat(nowTime).concat(".xlsx");
        response.setContentType(CONTENT_TYPE);
        //设置字符集为utf-8
        response.setCharacterEncoding(CHARACTER_UTF_8);

        //用postman测正常，浏览器多了filename_=utf-8等字样
//        response.setHeader(CONTENT_DISPOSITION,
//                "attachment;filename=" + URLEncoder.encode(fileName, CHARACTER_UTF_8)
//                        + ";filename*=utf-8''" + URLEncoder.encode(fileName, CHARACTER_UTF_8));

        //postman测会乱码，但浏览器下载就正常,真实开发是用这个，前端需要解码，文件名才能看到中文
        response.setHeader(CONTENT_DISPOSITION,
                "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        return response.getOutputStream();
    }

}
